/*
 * ===================================================================
 *  
 *      Filename:  log_client_mutex_sem.c
 *
 *   Description:  This file is the implement for the semphore.The sem
 *                 will be used to protect the shared memory.
 *
 *       Version:  1.0
 *        Create:  2010/07/13
 *
 *        Author:  Keven Zhu     kevenzhu@tencent.com
 *     Copyright:  Reserved by Tencent.com Co.ltd
 *          
 * ====================================================================
 */
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/sem.h>
#include <sys/stat.h>

#include "lib/util.h"
#include "log_client_api.h"

/* struct sembuf
 * short        sem_num
 * short        sem_op
 * short        sem_flg*/
struct sembuf  
    writer_p={
        .sem_num = 0,
        .sem_op  = -1,
        .sem_flg = 0}, 
    reader_p={
        .sem_num = 1,
        .sem_op  = -1,
        .sem_flg = 0}, 
    writer_v={
        .sem_num = 0,
        .sem_op  = 1,
        .sem_flg = 0}, 
    reader_v={
        .sem_num = 1,
        .sem_op  = 1,
        .sem_flg = 0}; 

int    hplog_mutex_sem  = INV_HANDLER;

/* post the semphore(unlock)
 *
 * return value:
 * positive means failure,error could be found in the head file or with the help of plogerr();
 * 0 means ok(launched)*/
int hplog_sem_wirter_post()
{
    if(hplog_mutex_sem == INV_HANDLER)
        return INVIO;
    if(-1 == semop(hplog_mutex_sem,&writer_v,1))
        return ERRMP;
    else
        return NOERR;
}

/* fetch the semphore(lock)
 *
 * return value:
 * positive means failure,error could be found in the head file or with the help of plogerr();
 * 0 means ok(launched)*/
int hplog_sem_writer_wait()
{
    if(hplog_mutex_sem == INV_HANDLER)
        return INVIO;
    if(-1 == semop(hplog_mutex_sem,&writer_p,1))
        return ERRMP;
    else
        return NOERR;
}

/* post the semphore(unlock)
 *
 * return value:
 * positive means failure,error could be found in the head file or with the help of plogerr();
 * 0 means ok(launched)*/
int hplog_sem_reader_post()
{
    if(hplog_mutex_sem == INV_HANDLER)
        return INVIO;
    if(-1 == semop(hplog_mutex_sem,&reader_v,1))
        return ERRMP;
    else
        return NOERR;
}

/* fetch the semphore(lock)
 *
 * return value:
 * positive means failure,error could be found in the head file or with the help of plogerr();
 * 0 means ok(launched)*/
int hplog_sem_reader_wait()
{
    if(hplog_mutex_sem == INV_HANDLER)
        return INVIO;
    if(-1 == semop(hplog_mutex_sem,&reader_p,1))
        return ERRMP;
    else
        return NOERR;
}


/* initialze the mutex semphone
 *
 * return value:
 * positive means failure,error could be found in the head file or with the help of plogerr();
 * 0 means ok(launched)*/
int initialize_hplog_mutex_sem(int source)
{
    union semun 
    {
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO   */
    };
    union semun argv;
    key_t key = (key_t)HPLOG_SEM_KEY;
    hplog_mutex_sem = semget(key,2,IPC_CREAT|S_IRWXU|S_IRWXG|S_IRWXO);
    if(source == CLIENT_PROCESS)
    {
        if(-1 == hplog_mutex_sem)
        {   
            log_doctor(doctor_level,"client failed to initial the sem\n"); 
            return INVIO;
        }
        else
        {
            return FITSM;
        }
    }
    else
    {
        if(-1 == hplog_mutex_sem)
        {    
            log_doctor(doctor_level,"daemon failed to initial the sem\n");
            return INVIO;
        }
    }

    argv.val=1;/*reader mutex sem, keep the useable counter to 0*/
    if(semctl(hplog_mutex_sem,0,SETVAL,argv)==-1)
    {
        log_doctor(doctor_level,"error to set the writer sem\n");
        semctl(hplog_mutex_sem,0,IPC_RMID);
        return FSTSM;
    }
    argv.val=0;/*writer mutex sem, keep the useable counter to 1*/
    if(semctl(hplog_mutex_sem,1,SETVAL,argv)==-1)
    {
        log_doctor(doctor_level,"error to set the reader sem\n");
        semctl(hplog_mutex_sem,1,IPC_RMID);
        return FSTSM;
    }

    return NOERR;
}

int finitialize_hplog_mutex_sem()
{
    key_t key = (key_t)HPLOG_SEM_KEY;
    hplog_mutex_sem = semget(key,2,IPC_CREAT|S_IRWXU|S_IRWXG|S_IRWXO);
    if(-1 == hplog_mutex_sem)
    {
        return INVIO;
    }
    semctl(hplog_mutex_sem,1,IPC_RMID);
    return NOERR;
}
